package roteador;

import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

public class Roteador {

    private int id;
    private int porta;
    private List<Enlace> enlaces;
    private Thread comunicacao;
    private Listener listener;
    private BellmanFord BF;

    public Roteador(int id, int porta) throws SocketException {
        this.id = id;
        this.porta = porta;
        listener = new Listener(porta, this);
        enlaces = new ArrayList<Enlace>();
        BF = new BellmanFord(id);

        iniciaSocket();
    }

    private void iniciaSocket() {
        comunicacao = new Thread(listener, "Roteador " + getID()
                + " escutando na porta " + getPorta());
        comunicacao.start();
    }

    public void addEnlace(Roteador destino, int peso) {
        enlaces.add(new Enlace(this, destino.getID(), destino.getIP(), destino.getPorta(), peso));
        BF.addVizinho(new DistanciaRoteador(destino.getID(), peso, this.getID()));
        System.out.println("Criou enlace de: " + id + " para "
                + destino.getID());
        enviarTabela();
    }

    public byte[] getVetorDistancia() {
        return BF.getVetorDistancia();
    }

    synchronized void enviarTabela() {
        Timestamp time = new Timestamp(System.currentTimeMillis());

        byte[] messagemByte = getVetorDistancia();
        byte[] mEnviar = new byte[1024];
        for (int i = 0; i < messagemByte.length; i++) {
            mEnviar[i] = messagemByte[i];
        }

        System.out.println(time + " - " + new String(mEnviar));

        for (Enlace enlace : enlaces) {
            enlace.envia(mEnviar);

        }
    }

    public int getID() {
        return this.id;
    }

    public int getPorta() {
        return this.porta;
    }

    public void reiniciarTimeout(int idDestino) {
        for (Enlace enlace : enlaces) {
            if (enlace.getDestinoID() == idDestino) {
                //System.out.println("O roteador " +id+" reniciou o enlace " + idDestino);
                enlace.reiniciar();
                break;
            }
        }
    }

    public void cancelarEnlace(Enlace enlace) {
        if (enlaces.remove(enlace)) {

            removerVizinho(enlace.getDestinoID());
        }


    }

    public void cancelar() {
        System.out.println("Finalizando o roteador: " + this.id);
        listener.cancelar();

        for (Enlace enlace : enlaces) {
            enlace.cancelar();
        }
    }

    public InetAddress getIP() {
        try {
            return InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return null;
    }

    public void removerVizinho(int idVizinho) {

        if (BF.removerVizinho(idVizinho)) {
            System.out.println("o roteador " + id + " removeu o vizinho " + idVizinho);
            enviarTabela();
        }

    }

    public void atualizarListaRoteamento(ListaDeRoteamento lr) {
        if (BF.atualizarTabelaVizinho(lr)) {
            enviarTabela();
        }
    }

    public Enlace getEnlace(int o, int d) {
        for (Enlace enlace : enlaces) {
            if (enlace.getOrigemID() == o && enlace.getDestinoID() == d) {
                return enlace;
            }
        }
        return null;
    }

    public void setPesoEnlace(int origem, int destino, int custo) {
        Enlace enlace = getEnlace(origem, destino);
        if (enlace != null) {
            enlace.setPeso(custo);
            BF.atualizarListaRoteamento(new DistanciaRoteador(destino, custo, destino));
            System.out.println("Mudou enlace");
            enviarTabela();
        } else {
            System.out.println("Não existe enlace");
        }
    }
}
